#ifndef __PROCESS_POOL_HPP__
#define __PROCESS_POOL_HPP__
#include <iostream>
#include <cstdlib> // stdlib.h stdio.h -> cstdlib cstdio
#include <vector>
#include <unistd.h>
#include <sys/wait.h>
#include "Task.hpp"
#include<string>
//先描述，创建一个信道
class Channel
{
public:
   Channel(int fd,pid_t id ):_wfd(fd),_subid(id) 
   {
    
       _name = "Channel-" + std::to_string(_wfd) + "-" + std::to_string(_subid);   //等会查查其中该函数的用发 
   }
   ~Channel()
   {
         //因为没有开辟资源，所以这个没啥用
   }
   void Send(int code)
   {
       int n = write(_wfd,&code,sizeof(code));
       (void)n;  //让n也显得有活干，避免因为没有使用n然后报错了
   }
   void Close()  
   {
       close(_wfd); //关闭相应的文件描述符
   }
   void Wait()
   {
       pid_t pid = waitpid(_subid,nullptr,0);
   }
   std::string Name()
   {
    return _name;
   }

private:
   int _wfd; //代表的文件描述符
   pid_t _subid; //代表着子进程的pid
   std :: string _name;  //信道的名字
};

//在组织，通过vector顺序表把所有的信道组织到一起
class ChannelManager
{
public:
    ChannelManager(): _next(0)
    {}
    void Insert(int fd,pid_t id)
    {
        _channels.emplace_back(fd,id);  //记录新的信道
    }
    //通过轮询的手段让每一个信道依次干活
    Channel& Select()
    {
        auto& c = _channels[_next];
        _next = (_next + 1) % _channels.size(); // 轮着来
        return c;
    }
    void StopSubProcess()
    {
        for(auto& e : _channels)
        {
            e.Close(); //依次关闭每一个信道
            std::cout << "关闭: " << e.Name() << std::endl;
        }
    }
    void WaitSubProcess()
    {
        for(auto& e : _channels)
        {
            e.Wait();
            std::cout << "回收: " << e.Name() << std::endl;
        }
    }
    void PrintChannel()
    {
        for(auto& e : _channels)
        {
            std :: cout << e.Name() << std :: endl;
        }
    }
    ~ChannelManager()
    {}  //析构函数不用写，因为没有资源的使用
private:
   std::vector<Channel> _channels; //把所有的信号变成一个顺序表
   int _next;
};


//开始写最后一个类，掌柜的类（父进程），掌控

class ProcessPool
{
public:
    ProcessPool(int num) : _process_num(num)
    {
        _tm.Register(PrintLog);
        _tm.Register(Download);
        _tm.Register(Upload);
    }
    void Work(int fid)
    {
        while(true){
        int code = 0;  //当读到0的时候，会停止继续读
        ssize_t n = read(fid,&code,sizeof(code));
        if(n > 0)
        {
            if(n != sizeof(code)) continue;
            std::cout << "子进程[" << getpid() << "]收到一个任务码: " << code << std::endl;
            _tm.Excute(code);
        }
        else if(n == 0)
        {
            std :: cout << "子进程退出" << std :: endl;
            break;
        }
        else
        {
            std :: cout << "进程错误" << std :: endl;
            break;
        }
    }
    }
    bool Start()
    {
        //循环的开启信道
        for(int i = 0 ; i < _process_num ; i++)
        {
            //1.创建信道
            int fd[2] = {0};
            int n = pipe(fd);
            if(n < 0) return false;
            //2.创建子进程
            pid_t id = fork();
            //子进程，进行读数据
            if(id == 0)
            {
                //关闭没有必要的文件操作符
                close(fd[1]); //把写的端口关掉
                //执行工作
                Work(fd[0]);
                close(fd[0]); //干完活直接关掉就可以了
                exit(0);
            }
            else
            {
                //父进程执行写的工作
                //关掉一些没有必要的接口
                close(fd[0]); //把读的接口给关掉
                _cm.Insert(fd[1],id);
            }
        }
        return true;
    }
    void Debug()
    {
        _cm.PrintChannel();
    }
    void Run()
    {
        //1.选择一个任务
        int taskcode = _tm.Code();
        //2.选择其中一个信道
        auto&c = _cm.Select();
        std :: cout << "选择了一个子进程："<< c.Name() << std::endl;
        //发送一个任务
        std :: cout << "发送了一个任务码：" << taskcode << std :: endl;
        c.Send(taskcode);
    }
    void Stop()
    {
        //关闭父进程所有的fd（文件描述符）
        _cm.StopSubProcess();
        //进程等待
        _cm.WaitSubProcess();
    }
    ~ProcessPool()
    {}
private:
    ChannelManager _cm;
    int _process_num; //记录有多少个信道
    TaskManger _tm;
};





#endif